package com.yykj.user.center.server.service.impl.patient;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;
import com.github.wxpay.sdk.WxConfigCustom;
import com.yykj.common.bean.NotifyMsgContent;
import com.yykj.common.dto.NotifyMessageDTO;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.service.RedisService;
import com.yykj.common.service.TencentService;
import com.yykj.common.util.GsonUtil;
import com.yykj.common.util.LocalRequestUtil;
import com.yykj.common.util.LocalStringUtil;
import com.yykj.common.util.RandomUtil;
import com.yykj.hospital.client.dto.DoctorDTO;
import com.yykj.hospital.client.feign.HospitalServerFeignClient;
import com.yykj.message.center.client.enums.OrderType;
import com.yykj.message.center.client.feign.MessageFeignClient;
import com.yykj.pay.center.client.dto.ClientPayConfigDTO;
import com.yykj.pay.center.client.feign.PayFeignClient;
import com.yykj.user.center.server.constant.Constant;
import com.yykj.user.center.server.constant.YyWxConfig;
import com.yykj.user.center.server.dto.ConsultationInfoDTO;
import com.yykj.user.center.server.dto.UserLoginInfo;
import com.yykj.user.center.server.form.TextMsgContent;
import com.yykj.user.center.server.model.*;
import com.yykj.user.center.server.repository.GroupRepository;
import com.yykj.user.center.server.repository.RelationGroupPatientRepository;
import com.yykj.user.center.server.repository.patient.ConsultationInfoRepository;
import com.yykj.user.center.server.repository.patient.FileRepository;
import com.yykj.user.center.server.repository.patient.PatientRepository;
import com.yykj.user.center.server.service.TpnsService;
import com.yykj.user.center.server.service.patient.PaymentService;
import com.yykj.user.center.server.utils.DateUtil;
import com.yykj.user.center.server.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author chenl
 * @version 1.0
 * @date 2021/11/4 19:41
 */
@Service
@Slf4j
public class PaymentServiceImpl implements PaymentService {
    @Autowired
    private RedisService redisService;
    @Autowired
    private PatientRepository patientRepository;
    @Autowired
    private ConsultationInfoRepository consultationInfoRepository;
    @Autowired
    private RelationGroupPatientRepository relationGroupPatientRepository;
    @Autowired
    private GroupRepository groupRepository;
    /* @Autowired
     private WXPay wxPay;*/
    @Autowired
    private HospitalServerFeignClient hospitalServerFeignClient;
    @Autowired
    private TencentService tencentService;
    @Autowired
    private FileRepository fileRepository;
    @Autowired
    private MessageFeignClient messageFeignClient;
    @Autowired
    TpnsService tpnsService;
    @Value("${pay.callbackDomain}")
    public String callbackDomain;

    @Autowired
    PayFeignClient payFeignClient;

    @Override
    public Map<String, String> consultationPay(String orderNo) {
        try {
            String token = LocalRequestUtil.getToken();
            UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token), UserLoginInfo.class);
            ClientPayConfigDTO clientPayConfigDTO = this.payFeignClient.get(userLoginInfo.getHospitalId() + "");
            log.info("微信下单:hospitalId:" + userLoginInfo.getHospitalId());
            if (clientPayConfigDTO == null) {
                throw new RuntimeException("该医院配置不存在");
            }
            WxConfigCustom config = new WxConfigCustom(clientPayConfigDTO.getClientAppId(), clientPayConfigDTO.getClientMchId(), clientPayConfigDTO.getClientMechKey());
            log.info("微信支付参数:{},{},{}",clientPayConfigDTO.getClientAppId(), clientPayConfigDTO.getClientMchId(), clientPayConfigDTO.getClientMechKey());
            WXPay wxPay = new WXPay(config);
            String accountId = userLoginInfo.getUserId();
            Patient patient = patientRepository.findById(accountId).orElse(null);
            if (patient == null) {
                throw new NormalException(ResultEnums.NO_ACCOUNT_ERROR);
            }
            ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.findFirstByPayAccountIdAndOrderNo(accountId, orderNo);
            if (consultationInfoOrder == null) {
                throw new NormalException(ResultEnums.NO_ORDER_ERROR);
            }
            if (consultationInfoOrder.getPayStatus().intValue() != 0) {
                throw new NormalException(ResultEnums.ORDER_ABNORMAL);
            }
            consultationInfoOrder.setPayType(1);
            consultationInfoRepository.save(consultationInfoOrder);
            // 1. 拼接统⼀下单地址参数
            Map<String, String> paraMap = new HashMap<String, String>();
            paraMap.put("openid", patient.getOpenid());//用户标识
            paraMap.put("body", "预约挂号"); // 商品描述
            paraMap.put("out_trade_no", consultationInfoOrder.getOrderNo());// 订单号
            //金额转换
            BigDecimal fen = consultationInfoOrder.getPayAmount().multiply(new BigDecimal("100")); //1.00
            fen = fen.setScale(0, BigDecimal.ROUND_UP);
            paraMap.put("total_fee", fen.intValue() + ""); // ⽀付⾦额，单位分，即0.01元
            paraMap.put("notify_url", callbackDomain + "user-center/api/payment/notify/" + orderNo);//支付结果通知地址
            paraMap.put("trade_type", "JSAPI"); // 交易类型
            log.info("统一下单请求参数:{}", JSON.toJSONString(paraMap));
            //2.发送post请求"统⼀下单接⼝", 返回预⽀付id:prepay_id
            Map<String, String> map = wxPay.unifiedOrder(paraMap);
            //3.将数据组合,再次签名
            Map<String, String> payMap = new HashMap<String, String>();
            String prepayId = (String) map.get("prepay_id");
            if ("OK".equals(map.get("return_msg"))) {
                payMap.put("appId", YyWxConfig.APP_ID);
                payMap.put("timeStamp", WXPayUtil.getCurrentTimestamp() + "");
                payMap.put("nonceStr", WXPayUtil.generateNonceStr());
                payMap.put("signType", WXPayConstants.HMACSHA256);
                payMap.put("package", "prepay_id=" + prepayId);
                //通过appId, timeStamp, nonceStr, signType, package及商户密钥进⾏key=value形式拼接并加密
                String paySign = WXPayUtil.generateSignature(payMap, YyWxConfig.KEY, WXPayConstants.SignType.HMACSHA256);
                payMap.put("paySign", paySign);
                log.info("wxPay支付请求参数 => {}", JSON.toJSONString(payMap));
                log.info("调用统一下单接口,成功！");
            } else {
                log.error("调用统一下单接口,失败！");
                throw new NormalException(ResultEnums.ORDER_ERROR);
            }
            return payMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new NormalException(ResultEnums.TASK_DATA_ERROR);
        }


    }

    @Override
    public void notify(String orderNo, String xml) {
        success(orderNo);
    }

    @Override
    public void success(String orderNo) {
        try {
            ConsultationInfoOrder consultationInfoOrder = consultationInfoRepository.findFirstByOrderNo(orderNo);
            if (consultationInfoOrder == null) {
                throw new NormalException(ResultEnums.NO_EXIST_ORDERNO_ERROR, String.format("订单【%s】不存在", orderNo));
            }
            if (consultationInfoOrder.getPayStatus() == 1) {
                log.info("回调功能，订单号：{},患者已支付", orderNo);
                return;
            }
            String patientCardId = consultationInfoOrder.getPatientCardId();
            String doctorId = consultationInfoOrder.getDoctorId();
            List<RelationGroupPatient> relationGroupPatients = relationGroupPatientRepository.findAllByPatientCardIdAndDoctorId(patientCardId, doctorId);
//            if(relationGroupPatients.size()==0){
            Integer hospitalId = consultationInfoOrder.getHospitalId();
            RelationGroupPatient relationGroupPatient = new RelationGroupPatient();
            Group group = groupRepository.findFirstByHospitalIdAndDoctorIdAndIsDefaultAndState(hospitalId, doctorId, true, true);
            if (group != null) {
                relationGroupPatient.setGroupId(group.getId());
                relationGroupPatient.setDoctorId(doctorId);
                relationGroupPatient.setId(LocalStringUtil.getUUID());
                relationGroupPatient.setPatientCardId(patientCardId);
                relationGroupPatient.setPatientName(consultationInfoOrder.getPatientName());
                relationGroupPatient.setHospitalId(hospitalId);
                relationGroupPatient.setName(group.getName());
                relationGroupPatient.setAge(consultationInfoOrder.getAge());
                relationGroupPatient.setSex(consultationInfoOrder.getSex());
                relationGroupPatient.setType(1);
                relationGroupPatientRepository.save(relationGroupPatient);
            }
//            }
            consultationInfoOrder.setPayStatus(1);
            consultationInfoOrder.setState(1);
            consultationInfoRepository.save(consultationInfoOrder);
            log.info("回调功能，订单号：{},回调成功", orderNo);
            Long time = Long.valueOf(Constant.TIMEOUT);
            if (!redisService.lock(consultationInfoOrder.getId().toString(), String.valueOf(time))) {
                throw new NormalException(ResultEnums.PUSH_PURCHASE_FAILED);
            }
            //发送给患者系统消息
            sendConsultationMsgToPatient(consultationInfoOrder);
            //发送给医生系统消息
            sendConsultationMsgToDoctor(consultationInfoOrder);
            //医生给患者发送消息:支付已经成功的消息
            //1表示支付成功提示信息 2表示患者信息 3表示支付成功系统提醒
            Map dataMap = new HashMap();
            dataMap.put("type", 1);
            dataMap.put("data", "支付成功！医生接诊后将会短信通知您，请在预约时段注意接收医生的图文及音视频消息");
            sendPayedMsg(consultationInfoOrder.getDoctorTencentAccountId(), consultationInfoOrder.getPatientTencentAccountId(), JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 2);
            //患者给医生发送消息：支付已成功的消息
            dataMap.put("type", 1);
            dataMap.put("data", "患者已支付成功！请在预约时段内接诊");
            sendPayedMsg(consultationInfoOrder.getPatientTencentAccountId(), consultationInfoOrder.getDoctorTencentAccountId(), JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 2);
            //患者给医生发送消息，患者问诊详情信息
            ConsultationInfoDTO consultationInfoDTO = new ConsultationInfoDTO();
            BeanUtils.copyProperties(consultationInfoOrder, consultationInfoDTO);
            List<File> files = fileRepository.findAllByBusinessId(consultationInfoOrder.getId());
            List<String> paths = files.stream().map(File::getPath).collect(Collectors.toList());
            consultationInfoDTO.setImgs(paths);
            dataMap.put("type", 2);
            dataMap.put("data", consultationInfoDTO);
            sendPayedMsg(consultationInfoOrder.getPatientTencentAccountId(), consultationInfoOrder.getDoctorTencentAccountId(), JSON.toJSONString(dataMap, SerializerFeature.WriteNullStringAsEmpty), 1);
            redisService.unlock(consultationInfoOrder.getId().toString(), String.valueOf(time));
            log.info("回调功能后消息发送成功，订单号：{},消息发送成功", orderNo);
            this.messageFeignClient.sendOrderPaySuccessMessage(orderNo, OrderType.consultation);

            //tpns
            this.tpnsService.sendPaySuccess(consultationInfoOrder.getDoctorTencentAccountId(), consultationInfoOrder.getOrderType());


        } catch (Exception e) {
            log.error("回调功能，订单号：{},回调失败", orderNo);
        }
    }

    @Override
    public void refund(String order) {
        ConsultationInfoOrder consultationInfoOrder = this.consultationInfoRepository.findFirstByOrderNo(order);
        if (this.payFeignClient.refund(order, consultationInfoOrder.getHospitalId())) {
            consultationInfoOrder.setState(4);
            consultationInfoOrder.setRefundTime(LocalDateTime.now());
            this.consultationInfoRepository.save(consultationInfoOrder);
        }

        throw new RuntimeException("退款失败");
    }

    @Override
    public void sendPayedMsg(String fromId, String toId, String msg, Integer SyncOtherMachine) {
        NotifyMessageDTO notifyMessageDTO = new NotifyMessageDTO();
        notifyMessageDTO.setFrom_Account(fromId);
        notifyMessageDTO.setSyncOtherMachine(SyncOtherMachine);
        notifyMessageDTO.setTo_Account(toId);
        notifyMessageDTO.setMsgRandom(Integer.valueOf(RandomUtil.randomNumbers(8)));
        NotifyMsgContent notifyMsgContent = new NotifyMsgContent();
        notifyMsgContent.setMsgType("TIMCustomElem");
        notifyMessageDTO.setMsgSeq(Integer.valueOf(createSeq()));
        TextMsgContent textMsgContent = new TextMsgContent();
//            Map<String, String> msgContent = new HashMap<>();
        log.info("Text ==>{}", JSON.toJSONString(msg));
        textMsgContent.setData(msg);
        textMsgContent.setSound("dingdong.aiff");
        notifyMsgContent.setMsgContent(textMsgContent);
        List<NotifyMsgContent> notifyMsgContents = new ArrayList<>();
        notifyMsgContents.add(notifyMsgContent);
        notifyMessageDTO.setCloudCustomData(msg);
        notifyMessageDTO.setMsgBody(notifyMsgContents);
        tencentService.sendNotifyMessage(notifyMessageDTO);
    }

    public void sendConsultationMsgToPatient(ConsultationInfoOrder consultationInfoOrder) {
        String num = createSeq();
        NotifyMessageDTO notifyMessageDTO = new NotifyMessageDTO();
        notifyMessageDTO.setSyncOtherMachine(2);
        notifyMessageDTO.setTo_Account(consultationInfoOrder.getPatientTencentAccountId());
        notifyMessageDTO.setMsgRandom(Integer.valueOf(RandomUtil.randomNumbers(8)));
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        NotifyMsgContent notifyMsgContent = new NotifyMsgContent();
        notifyMsgContent.setMsgType("TIMCustomElem");
        notifyMessageDTO.setMsgSeq(Integer.valueOf(createSeq()));
        TextMsgContent textMsgContent = new TextMsgContent();
//            Map<String, String> msgContent = new HashMap<>();
        Map<String, String> textMap = new HashMap<>();
        textMap.put("id", consultationInfoOrder.getId());
        String smsOrderType = "";
        if (consultationInfoOrder.getOrderType() == 11) {
            smsOrderType = "图文";
            textMsgContent.setDesc("图文问诊支付成功");
            textMap.put("title", "图文问诊支付成功");
            textMap.put("doctorId", consultationInfoOrder.getDoctorTencentAccountId());
            textMap.put("content", "您已预约" + consultationInfoOrder.getDoctorName() + "医生的图文问诊，请注意问诊时间按期问诊。问诊时间：" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()));
        } else if (consultationInfoOrder.getOrderType() == 12) {
            smsOrderType = "语音";
            textMsgContent.setDesc("语音问诊支付成功");
            textMap.put("title", "语音问诊支付成功");
            textMap.put("doctorId", consultationInfoOrder.getDoctorTencentAccountId());
            textMap.put("content", "您已预约" + consultationInfoOrder.getDoctorName() + "医生的语音问诊，请注意问诊时间按期问诊。问诊时间：" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()));
        } else if (consultationInfoOrder.getOrderType() == 13) {
            smsOrderType = "视频";
            textMsgContent.setDesc("视频问诊支付成功");
            textMap.put("title", "视频问诊支付成功");
            textMap.put("doctorId", consultationInfoOrder.getDoctorTencentAccountId());
            textMap.put("content", "您已预约" + consultationInfoOrder.getDoctorName() + "医生的视频问诊，请注意问诊时间按期问诊。问诊时间：" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()));
        }
        //sms
        DoctorDTO doctorDTO = this.hospitalServerFeignClient.info(consultationInfoOrder.getDoctorId());
        if (doctorDTO != null && StringUtils.isNotBlank(doctorDTO.getMobile())) {
            messageFeignClient.smsDoctorPaySuccess(doctorDTO.getMobile(), smsOrderType, StringUtil.LocalDateTime2String(consultationInfoOrder.getStartDatetime()));
            Optional<Patient> optional = this.patientRepository.findById(consultationInfoOrder.getPayAccountId());
            if (optional.isPresent()) {
                messageFeignClient.smsPatientPaySuccess(optional.get().getMobile(), consultationInfoOrder.getDoctorName(), smsOrderType);
            }
        }
        log.info("Text ==>{}", JSON.toJSONString(textMap));
        textMsgContent.setData(JSON.toJSONString(textMap));
        textMsgContent.setSound("dingdong.aiff");
        notifyMsgContent.setMsgContent(textMsgContent);
        List<NotifyMsgContent> notifyMsgContents = new ArrayList<>();
        notifyMsgContents.add(notifyMsgContent);
        notifyMessageDTO.setCloudCustomData(JSON.toJSONString(textMap));
        notifyMessageDTO.setMsgBody(notifyMsgContents);
        tencentService.sendNotifyMessage(notifyMessageDTO);
    }

    public void sendConsultationMsgToDoctor(ConsultationInfoOrder consultationInfoOrder) {
        NotifyMessageDTO notifyMessageDTO = new NotifyMessageDTO();
        notifyMessageDTO.setSyncOtherMachine(2);
        notifyMessageDTO.setTo_Account(consultationInfoOrder.getDoctorTencentAccountId());
        notifyMessageDTO.setMsgRandom(Integer.valueOf(RandomUtil.randomNumbers(8)));
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        NotifyMsgContent notifyMsgContent = new NotifyMsgContent();
        notifyMsgContent.setMsgType("TIMCustomElem");
        notifyMessageDTO.setMsgSeq(Integer.valueOf(createSeq()));
        TextMsgContent textMsgContent = new TextMsgContent();
//            Map<String, String> msgContent = new HashMap<>();
        Map<String, String> textMap = new HashMap<>();
        textMap.put("id", consultationInfoOrder.getId());
        if (consultationInfoOrder.getOrderType() == 11) {
            textMsgContent.setDesc("图文问诊支付成功");
            textMap.put("accountId", consultationInfoOrder.getPatientTencentAccountId());
            textMap.put("title", "图文问诊支付成功");
            String msg = "您有一个" + consultationInfoOrder.getPatientName() + " 的图文问诊订单，预约时间为" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()) + "。请在预约时间内立即与患者进行沟通。";
            textMap.put("content", msg);
//            textMap.put("content", "您已预约" + consultationInfoOrder.getDoctorName() + "医生的图文问诊，请注意问诊时间按期问诊。问诊时间：" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()));
        } else if (consultationInfoOrder.getOrderType() == 12) {
            textMsgContent.setDesc("语音问诊支付成功");
            textMap.put("title", "语音问诊支付成功");
            textMap.put("accountId", consultationInfoOrder.getPatientTencentAccountId());
            String msg = "您有一个" + consultationInfoOrder.getPatientName() + " 的语音问诊订单，预约时间为" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()) + "。请在预约时间内立即与患者进行沟通。";
            textMap.put("content", msg);
//            textMap.put("content", "您已预约" + consultationInfoOrder.getDoctorName() + "医生的语音问诊，请注意问诊时间按期问诊。问诊时间：" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()));
        } else if (consultationInfoOrder.getOrderType() == 13) {
            textMsgContent.setDesc("视频问诊支付成功");
            textMap.put("title", "视频问诊支付成功");
            textMap.put("accountId", consultationInfoOrder.getPatientTencentAccountId());
            String msg = "您有一个" + consultationInfoOrder.getPatientName() + " 的视频问诊订单，预约时间为" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()) + "。请在预约时间内立即与患者进行沟通。";
            textMap.put("content", msg);
//            textMap.put("content", "您已预约" + consultationInfoOrder.getDoctorName() + "医生的视频问诊，请注意问诊时间按期问诊。问诊时间：" + DateUtil.dateTimeToString(consultationInfoOrder.getStartDatetime()) + "-" + DateUtil.dateTimeToHourMinutes(consultationInfoOrder.getEndDatetime()));
        }
        log.info("Text ==>{}", JSON.toJSONString(textMap));
        textMsgContent.setData(JSON.toJSONString(textMap));
        textMsgContent.setSound("dingdong.aiff");
        notifyMsgContent.setMsgContent(textMsgContent);
        List<NotifyMsgContent> notifyMsgContents = new ArrayList<>();
        notifyMsgContents.add(notifyMsgContent);
        notifyMessageDTO.setCloudCustomData(JSON.toJSONString(textMap));
        notifyMessageDTO.setMsgBody(notifyMsgContents);
        tencentService.sendNotifyMessage(notifyMessageDTO);
    }

    public String createSeq() {
        String seq = redisService.get("MsgSeq");
        if (seq == null) {
            redisService.set("MsgSeq", "0");
            return "0";
        } else {
            Integer seqNum = Integer.valueOf(seq);
            String num = String.valueOf(seqNum++);
            redisService.set("MsgSeq", num);
            return num;
        }
    }

}
